home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyc (Python 2.4)
-
- _cvsid = '$Id: dbtables.py 36901 2004-08-08 00:54:21Z tim_one $'
- import re
- import sys
- import copy
- import xdrlib
- import random
- from types import ListType, StringType
- import cPickle as pickle
-
- try:
- from bsddb3.db import *
- except ImportError:
- from bsddb.db import *
-
-
- class TableDBError(StandardError):
- pass
-
-
- class TableAlreadyExists(TableDBError):
- pass
-
-
- class Cond:
- '''This condition matches everything'''
-
- def __call__(self, s):
- return 1
-
-
-
- class ExactCond(Cond):
- '''Acts as an exact match condition function'''
-
- def __init__(self, strtomatch):
- self.strtomatch = strtomatch
-
-
- def __call__(self, s):
- return s == self.strtomatch
-
-
-
- class PrefixCond(Cond):
- '''Acts as a condition function for matching a string prefix'''
-
- def __init__(self, prefix):
- self.prefix = prefix
-
-
- def __call__(self, s):
- return s[:len(self.prefix)] == self.prefix
-
-
-
- class PostfixCond(Cond):
- '''Acts as a condition function for matching a string postfix'''
-
- def __init__(self, postfix):
- self.postfix = postfix
-
-
- def __call__(self, s):
- return s[-len(self.postfix):] == self.postfix
-
-
-
- class LikeCond(Cond):
- """
- Acts as a function that will match using an SQL 'LIKE' style
- string. Case insensitive and % signs are wild cards.
- This isn't perfect but it should work for the simple common cases.
- """
-
- def __init__(self, likestr, re_flags = re.IGNORECASE):
- chars_to_escape = '.*+()[]?'
- for char in chars_to_escape:
- likestr = likestr.replace(char, '\\' + char)
-
- self.likestr = likestr.replace('%', '.*')
- self.re = re.compile('^' + self.likestr + '$', re_flags)
-
-
- def __call__(self, s):
- return self.re.match(s)
-
-
- _table_names_key = '__TABLE_NAMES__'
- _columns = '._COLUMNS__'
-
- def _columns_key(table):
- return table + _columns
-
- _data = '._DATA_.'
- _rowid = '._ROWID_.'
- _rowid_str_len = 8
-
- def _data_key(table, col, rowid):
- return table + _data + col + _data + rowid
-
-
- def _search_col_data_key(table, col):
- return table + _data + col + _data
-
-
- def _search_all_data_key(table):
- return table + _data
-
-
- def _rowid_key(table, rowid):
- return table + _rowid + rowid + _rowid
-
-
- def _search_rowid_key(table):
- return table + _rowid
-
-
- def contains_metastrings(s):
- '''Verify that the given string does not contain any
- metadata strings that might interfere with dbtables database operation.
- '''
- if s.find(_table_names_key) >= 0 and s.find(_columns) >= 0 and s.find(_data) >= 0 or s.find(_rowid) >= 0:
- return 1
- else:
- return 0
-
-
- class bsdTableDB:
-
- def __init__(self, filename, dbhome, create = 0, truncate = 0, mode = 384, recover = 0, dbflags = 0):
- '''bsdTableDB.open(filename, dbhome, create=0, truncate=0, mode=0600)
- Open database name in the dbhome BerkeleyDB directory.
- Use keyword arguments when calling this constructor.
- '''
- self.db = None
- myflags = DB_THREAD
- if create:
- myflags |= DB_CREATE
-
- flagsforenv = DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | dbflags
-
- try:
- dbflags |= DB_AUTO_COMMIT
- except AttributeError:
- pass
-
- if recover:
- flagsforenv = flagsforenv | DB_RECOVER
-
- self.env = DBEnv()
- self.env.set_lk_detect(DB_LOCK_DEFAULT)
- self.env.open(dbhome, myflags | flagsforenv)
- if truncate:
- myflags |= DB_TRUNCATE
-
- self.db = DB(self.env)
- self.db.set_get_returns_none(1)
- self.db.set_flags(DB_DUP)
- self.db.open(filename, DB_BTREE, dbflags | myflags, mode)
- self.dbfilename = filename
- txn = self.env.txn_begin()
-
- try:
- if not self.db.has_key(_table_names_key, txn):
- self.db.put(_table_names_key, pickle.dumps([], 1), txn = txn)
- except:
- txn.abort()
- raise
-
- txn.commit()
- self._bsdTableDB__tablecolumns = { }
-
-
- def __del__(self):
- self.close()
-
-
- def close(self):
- if self.db is not None:
- self.db.close()
- self.db = None
-
- if self.env is not None:
- self.env.close()
- self.env = None
-
-
-
- def checkpoint(self, mins = 0):
-
- try:
- self.env.txn_checkpoint(mins)
- except DBIncompleteError:
- pass
-
-
-
- def sync(self):
-
- try:
- self.db.sync()
- except DBIncompleteError:
- pass
-
-
-
- def _db_print(self):
- '''Print the database to stdout for debugging'''
- print '******** Printing raw database for debugging ********'
- cur = self.db.cursor()
-
- try:
- (key, data) = cur.first()
- while None:
- print repr({
- key: data })
- next = cur.next()
- if next:
- (key, data) = next
- continue
- cur.close()
- return None
- except DBNotFoundError:
- cur.close()
-
-
-
- def CreateTable(self, table, columns):
- '''CreateTable(table, columns) - Create a new table in the database
- raises TableDBError if it already exists or for other DB errors.
- '''
- if not isinstance(columns, ListType):
- raise AssertionError
- txn = None
-
- try:
- if contains_metastrings(table):
- raise ValueError('bad table name: contains reserved metastrings')
-
- for column in columns:
- if contains_metastrings(column):
- raise ValueError('bad column name: contains reserved metastrings')
- continue
-
- columnlist_key = _columns_key(table)
- if self.db.has_key(columnlist_key):
- raise TableAlreadyExists, 'table already exists'
-
- txn = self.env.txn_begin()
- self.db.put(columnlist_key, pickle.dumps(columns, 1), txn = txn)
- tablelist = pickle.loads(self.db.get(_table_names_key, txn = txn, flags = DB_RMW))
- tablelist.append(table)
- self.db.delete(_table_names_key, txn)
- self.db.put(_table_names_key, pickle.dumps(tablelist, 1), txn = txn)
- txn.commit()
- txn = None
- except DBError:
- dberror = None
- if txn:
- txn.abort()
-
- raise TableDBError, dberror[1]
-
-
-
- def ListTableColumns(self, table):
- """Return a list of columns in the given table.
- [] if the table doesn't exist.
- """
- if not isinstance(table, StringType):
- raise AssertionError
- if contains_metastrings(table):
- raise ValueError, 'bad table name: contains reserved metastrings'
-
- columnlist_key = _columns_key(table)
- if not self.db.has_key(columnlist_key):
- return []
-
- pickledcolumnlist = self.db.get(columnlist_key)
- if pickledcolumnlist:
- return pickle.loads(pickledcolumnlist)
- else:
- return []
-
-
- def ListTables(self):
- '''Return a list of tables in this database.'''
- pickledtablelist = self.db.get(_table_names_key)
- if pickledtablelist:
- return pickle.loads(pickledtablelist)
- else:
- return []
-
-
- def CreateOrExtendTable(self, table, columns):
- '''CreateOrExtendTable(table, columns)
-
- - Create a new table in the database.
- If a table of this name already exists, extend it to have any
- additional columns present in the given list as well as
- all of its current columns.
- '''
- if not isinstance(columns, ListType):
- raise AssertionError
-
- try:
- self.CreateTable(table, columns)
- except TableAlreadyExists:
- txn = None
-
- try:
- columnlist_key = _columns_key(table)
- txn = self.env.txn_begin()
- oldcolumnlist = pickle.loads(self.db.get(columnlist_key, txn = txn, flags = DB_RMW))
- oldcolumnhash = { }
- for c in oldcolumnlist:
- oldcolumnhash[c] = c
-
- newcolumnlist = copy.copy(oldcolumnlist)
- for c in columns:
- if not oldcolumnhash.has_key(c):
- newcolumnlist.append(c)
- continue
-
- if newcolumnlist != oldcolumnlist:
- self.db.delete(columnlist_key, txn)
- self.db.put(columnlist_key, pickle.dumps(newcolumnlist, 1), txn = txn)
-
- txn.commit()
- txn = None
- self._bsdTableDB__load_column_info(table)
- except DBError:
- dberror = None
- if txn:
- txn.abort()
-
- raise TableDBError, dberror[1]
- except:
- None<EXCEPTION MATCH>DBError
-
-
- None<EXCEPTION MATCH>DBError
-
-
-
- def __load_column_info(self, table):
- '''initialize the self.__tablecolumns dict'''
-
- try:
- tcolpickles = self.db.get(_columns_key(table))
- except DBNotFoundError:
- raise TableDBError, 'unknown table: %r' % (table,)
-
- if not tcolpickles:
- raise TableDBError, 'unknown table: %r' % (table,)
-
- self._bsdTableDB__tablecolumns[table] = pickle.loads(tcolpickles)
-
-
- def __new_rowid(self, table, txn):
- '''Create a new unique row identifier'''
- unique = 0
- while not unique:
- p = xdrlib.Packer()
- p.pack_int(int(random.random() * 2147483647))
- p.pack_int(int(random.random() * 2147483647))
- newid = p.get_buffer()
-
- try:
- self.db.put(_rowid_key(table, newid), None, txn = txn, flags = DB_NOOVERWRITE)
- except DBKeyExistError:
- continue
-
- unique = 1
- return newid
-
-
- def Insert(self, table, rowdict):
- '''Insert(table, datadict) - Insert a new row into the table
- using the keys+values from rowdict as the column values.
- '''
- txn = None
-
- try:
- if not self.db.has_key(_columns_key(table)):
- raise TableDBError, 'unknown table'
-
- if not self._bsdTableDB__tablecolumns.has_key(table):
- self._bsdTableDB__load_column_info(table)
-
- for column in rowdict.keys():
- if not self._bsdTableDB__tablecolumns[table].count(column):
- raise TableDBError, 'unknown column: %r' % (column,)
- continue
-
- txn = self.env.txn_begin()
- rowid = self._bsdTableDB__new_rowid(table, txn = txn)
- for column, dataitem in rowdict.items():
- self.db.put(_data_key(table, column, rowid), dataitem, txn = txn)
-
- txn.commit()
- txn = None
- except DBError:
- dberror = None
- info = sys.exc_info()
- if txn:
- txn.abort()
- self.db.delete(_rowid_key(table, rowid))
-
- raise TableDBError, dberror[1], info[2]
-
-
-
- def Modify(self, table, conditions = { }, mappings = { }):
- """Modify(table, conditions) - Modify in rows matching 'conditions'
- using mapping functions in 'mappings'
- * conditions is a dictionary keyed on column names
- containing condition functions expecting the data string as an
- argument and returning a boolean.
- * mappings is a dictionary keyed on column names containint condition
- functions expecting the data string as an argument and returning the
- new string for that column.
- """
-
- try:
- matching_rowids = self._bsdTableDB__Select(table, [], conditions)
- columns = mappings.keys()
- for rowid in matching_rowids.keys():
- txn = None
-
- try:
- for column in columns:
- txn = self.env.txn_begin()
-
- try:
- dataitem = self.db.get(_data_key(table, column, rowid), txn)
- self.db.delete(_data_key(table, column, rowid), txn)
- except DBNotFoundError:
- dataitem = None
-
- dataitem = mappings[column](dataitem)
- if dataitem != None:
- self.db.put(_data_key(table, column, rowid), dataitem, txn = txn)
-
- txn.commit()
- txn = None
- continue
- except DBError:
- dberror = None
- if txn:
- txn.abort()
-
- raise
- continue
-
-
- except DBError:
- dberror = None
- raise TableDBError, dberror[1]
-
-
-
- def Delete(self, table, conditions = { }):
- '''Delete(table, conditions) - Delete items matching the given
- conditions from the table.
- * conditions is a dictionary keyed on column names
- containing condition functions expecting the data string as an
- argument and returning a boolean.
- '''
-
- try:
- matching_rowids = self._bsdTableDB__Select(table, [], conditions)
- columns = self._bsdTableDB__tablecolumns[table]
- for rowid in matching_rowids.keys():
- txn = None
-
- try:
- txn = self.env.txn_begin()
- for column in columns:
-
- try:
- self.db.delete(_data_key(table, column, rowid), txn)
- continue
- except DBNotFoundError:
- continue
-
-
-
-
- try:
- self.db.delete(_rowid_key(table, rowid), txn)
- except DBNotFoundError:
- None<EXCEPTION MATCH>DBNotFoundError
- None<EXCEPTION MATCH>DBNotFoundError
- except:
- None<EXCEPTION MATCH>DBNotFoundError
-
- txn.commit()
- txn = None
- continue
- except DBError:
- dberror = None
- if txn:
- txn.abort()
-
- raise
- continue
-
-
- except DBError:
- dberror = None
- raise TableDBError, dberror[1]
-
-
-
- def Select(self, table, columns, conditions = { }):
- '''Select(table, conditions) - retrieve specific row data
- Returns a list of row column->value mapping dictionaries.
- * columns is a list of which column data to return. If
- columns is None, all columns will be returned.
- * conditions is a dictionary keyed on column names
- containing callable conditions expecting the data string as an
- argument and returning a boolean.
- '''
-
- try:
- if not self._bsdTableDB__tablecolumns.has_key(table):
- self._bsdTableDB__load_column_info(table)
-
- if columns is None:
- columns = self._bsdTableDB__tablecolumns[table]
-
- matching_rowids = self._bsdTableDB__Select(table, columns, conditions)
- except DBError:
- dberror = None
- raise TableDBError, dberror[1]
-
- return matching_rowids.values()
-
-
- def __Select(self, table, columns, conditions):
- '''__Select() - Used to implement Select and Delete (above)
- Returns a dictionary keyed on rowids containing dicts
- holding the row data for columns listed in the columns param
- that match the given conditions.
- * conditions is a dictionary keyed on column names
- containing callable conditions expecting the data string as an
- argument and returning a boolean.
- '''
- if not self._bsdTableDB__tablecolumns.has_key(table):
- self._bsdTableDB__load_column_info(table)
-
- if columns is None:
- columns = self.tablecolumns[table]
-
- for column in columns + conditions.keys():
- if not self._bsdTableDB__tablecolumns[table].count(column):
- raise TableDBError, 'unknown column: %r' % (column,)
- continue
-
- matching_rowids = { }
- rejected_rowids = { }
-
- def cmp_conditions(atuple, btuple):
- a = atuple[1]
- b = btuple[1]
- if type(a) is type(b):
- if isinstance(a, PrefixCond) and isinstance(b, PrefixCond):
- return cmp(len(b.prefix), len(a.prefix))
-
- if isinstance(a, LikeCond) and isinstance(b, LikeCond):
- return cmp(len(b.likestr), len(a.likestr))
-
- return 0
-
- if isinstance(a, ExactCond):
- return -1
-
- if isinstance(b, ExactCond):
- return 1
-
- if isinstance(a, PrefixCond):
- return -1
-
- if isinstance(b, PrefixCond):
- return 1
-
- return 0
-
- conditionlist = conditions.items()
- conditionlist.sort(cmp_conditions)
- cur = self.db.cursor()
- column_num = -1
- for column, condition in conditionlist:
- column_num = column_num + 1
- searchkey = _search_col_data_key(table, column)
- if column in columns:
- savethiscolumndata = 1
- else:
- savethiscolumndata = 0
-
- try:
- (key, data) = cur.set_range(searchkey)
- while key[:len(searchkey)] == searchkey:
- rowid = key[-_rowid_str_len:]
- if not rejected_rowids.has_key(rowid):
- if not condition or condition(data):
- if not matching_rowids.has_key(rowid):
- matching_rowids[rowid] = { }
-
- if savethiscolumndata:
- matching_rowids[rowid][column] = data
-
- elif matching_rowids.has_key(rowid):
- del matching_rowids[rowid]
-
- rejected_rowids[rowid] = rowid
-
- (key, data) = cur.next()
- continue
- except DBError:
- dberror = None
- if dberror[0] != DB_NOTFOUND:
- raise
- continue
- continue
- continue
-
-
-
- cur.close()
- del rejected_rowids
- if len(columns) > 0:
- for rowid, rowdata in matching_rowids.items():
- for column in columns:
- if rowdata.has_key(column):
- continue
-
-
- try:
- rowdata[column] = self.db.get(_data_key(table, column, rowid))
- continue
- except DBError:
- dberror = None
- if dberror[0] != DB_NOTFOUND:
- raise
-
- rowdata[column] = None
- continue
-
-
-
-
-
- return matching_rowids
-
-
- def Drop(self, table):
- '''Remove an entire table from the database'''
- txn = None
-
- try:
- txn = self.env.txn_begin()
- self.db.delete(_columns_key(table), txn)
- cur = self.db.cursor(txn)
- table_key = _search_all_data_key(table)
- while None:
-
- try:
- (key, data) = cur.set_range(table_key)
- except DBNotFoundError:
- break
-
- if key[:len(table_key)] != table_key:
- break
-
- table_key = _search_rowid_key(table)
- while None:
-
- try:
- (key, data) = cur.set_range(table_key)
- except DBNotFoundError:
- break
-
- if key[:len(table_key)] != table_key:
- break
-
- cur.close()
- tablelist = pickle.loads(self.db.get(_table_names_key, txn = txn, flags = DB_RMW))
-
- try:
- tablelist.remove(table)
- except ValueError:
- pass
-
- self.db.delete(_table_names_key, txn)
- self.db.put(_table_names_key, pickle.dumps(tablelist, 1), txn = txn)
- txn.commit()
- txn = None
- if self._bsdTableDB__tablecolumns.has_key(table):
- del self._bsdTableDB__tablecolumns[table]
- except DBError:
- dberror = None
- if txn:
- txn.abort()
-
- raise TableDBError, dberror[1]
-
-
-
-